package com.fishsb19.asuscomm.hashtable;

import java.io.IOException;

import com.fishsb19.asuscomm.filereadandwrite.MyFileWriter;

public class MyHashTableInterface {
	private MyHashTable myHashTable;
	private int searchProbeCounter;
	private int searchInstructionCounter;
	private int loopingCounter;
	private MyFileWriter myWriter;

	/**
	 * Constructor Initialize parameter
	 * 
	 * @param dataLength
	 * @throws IOException
	 */
	public MyHashTableInterface(int hashTableSize) throws IOException {
		this.myHashTable = new MyHashTable(hashTableSize);
		this.myWriter = new MyFileWriter();
		System.out.println("This is my HASHTable Size  "
				+ this.myHashTable.getSize());
		this.myWriter
				.wirteTXT("This is the size of HashTable " + hashTableSize+"\n");
	}

	/**
	 * Main Hashing Function Get each char with the index as exponent and sum
	 * them
	 * 
	 * @param data
	 * @return
	 */
	public int getMainHashValue(String data) {
		int tempValue = 0;
		for (int tempCounter = 0; tempCounter < data.length(); tempCounter++) {
			tempValue = tempValue + data.codePointAt(tempCounter)
					* (data.length() - tempCounter + 6);
		}
		tempValue = (tempValue) % this.myHashTable.getSize();
		System.out.println("This is the hash value of " + data + "   "
				+ tempValue);
		this.myWriter.wirteTXT("This is the hash value of " + data + "   "
				+ tempValue+"\n");
		return tempValue;
	}

	/**
	 * Inserting Method Check whether the index(use the hash value modular the
	 * size of HashTable as index), if the first and secondary index are
	 * occupied, access each space of HashTable from the beginning to the end
	 * 
	 * @param data
	 */
	public void insertData(String data) {
		this.myWriter.wirteTXT("Start insert string "+data);
		// Check main hash value
		int tempValue = this.getMainHashValue(data);
		if (this.myHashTable.isOccupied(tempValue)) {
			// Go through all the HashTable
			int tempCounter = 0;
			while (tempCounter < this.myHashTable.getSize()) {
				++tempValue;
				if (tempValue >= this.myHashTable.getSize())
					tempValue = 0;
				if (this.myHashTable.isOccupied(tempValue)) {
					tempCounter++;
				} else {
					this.myHashTable.insertData(tempValue, data);
					System.out.println("Successfully inserted at "
							+ tempCounter + " in the hash table");
					this.myWriter.wirteTXT("Successfully inserted at "
							+ tempCounter + " in the hash table"+"\n");
					return;
				}
			}

		} else {
			this.myHashTable.insertData(tempValue, data);
			System.out.println("Successfully inserted at " + tempValue
					+ " in the hash table");
			this.myWriter.wirteTXT("Successfully inserted at " + tempValue
					+ " in the hash table"+"\n");
			return;
		}
	}

	/**
	 * Delete String Data Method Reuse the search method and use the return
	 * value as index of deleting , if the return value is negative one, it
	 * means no such string in the HashTable
	 * 
	 * @param targetData
	 */
	public void deleteData(String targetData) {
		this.myWriter.wirteTXT("This is the delete target string" + targetData);
		int tempValue = this.getMainHashValue(targetData);
		if (!this.myHashTable.getData(tempValue).equals(targetData)) {
			for (int tempCounter = 0; tempCounter < this.myHashTable.getSize(); tempCounter++) {
				++tempValue;
				if (tempValue >= this.myHashTable.getSize())
					tempValue = 0;
				if (this.myHashTable.getData(tempValue).equals("####")) {
					System.out
							.println("Could not found the string in the hashTable ,delete failed");
					this.myWriter
							.wirteTXT("Could not found the string in the hashTable ,delete failed"+"\n");
					return;
				}
				if (this.myHashTable.getData(tempValue).equals(targetData)) {
					System.out.println("Found target . It is at " + tempValue
							+ " of the HashTable");
					this.myWriter.wirteTXT("Found target . It is at "
							+ tempValue + " of the HashTable");
					this.myHashTable.deleteData(tempValue);
					System.out.println("Successfully deleted");
					this.myWriter
							.wirteTXT("Successfully deleted " + targetData+"\n");
					return;
				}
			}
			System.out
					.println("Could not found the string in the hash table, deleted failed");
			this.myWriter
					.wirteTXT("Could not found the string in the hashTable ,delete failed"+"\n");
			return;
		} else {
			System.out.println("Found target . It is at " + tempValue
					+ " of the HashTable");
			this.myWriter.wirteTXT("Found target . It is at " + tempValue
					+ " of the HashTable"+"\n");
			this.myHashTable.deleteData(tempValue);
			System.out.println("Successfully deleted");
			this.myWriter.wirteTXT("Successfully deleted " + targetData+"\n");
			return;
		}
	}

	/**
	 * Searching String Data Method Check whether the index(use the hash value
	 * modular the size of HashTable as index), if the first or secondary index
	 * is equaled, return the current index which is the target string's
	 * location in the HashTable. access each space of HashTable from the
	 * beginning to the end
	 * 
	 * @param data
	 */
	public void searchData(String data) {
		this.myWriter.wirteTXT("Start search the string "+data+"\n");
		this.searchInstructionCounter++;
		int tempValue = this.getMainHashValue(data);
		if (!this.myHashTable.getData(tempValue).equals(data)) {
			this.loopingCounter++;
			System.out.println("This String has called looping  " + data
					+ "  .");
			for (int tempCounter = 0; tempCounter < this.myHashTable.getSize(); tempCounter++) {
				++tempValue;
				if (tempValue >= this.myHashTable.getSize())
					tempValue = 0;
				if (this.myHashTable.getData(tempValue).equals("####")) {
					System.out
							.println("Could not found the string in the hashTable ");
					this.myWriter.wirteTXT("Could not found the string in the hashTable "+"\n");
					this.searchProbeCounter++;
					return ;
				}
				if (this.myHashTable.getData(tempValue).equals(data)) {
					System.out.println("Found target . It is at " + tempValue
							+ " of the HashTable, with " + tempCounter+1
							+ " looping");
					this.myWriter.wirteTXT("Found target . It is at " + tempValue
							+ " of the HashTable, with " + tempCounter
							+ " looping"+"\n");
					this.searchProbeCounter = this.searchProbeCounter
							+ tempCounter;
					return ;
				}
			}
			System.out.println("Could not found the string in the hash table");
			this.myWriter.wirteTXT("Could not found the string in the hashTable "+"\n");
			this.searchProbeCounter = this.searchProbeCounter
					+ this.myHashTable.getSize();
			return;
		} else {
			System.out.println("Found target . It is at " + tempValue
					+ " of the HashTable");
			this.myWriter.wirteTXT("Found target . It is at " + tempValue
					+ " of the HashTable, with no looping"+"\n");
			this.searchProbeCounter++;
			return ;
		}
	}

	/**
	 * checkHashTable Method Check all value in the HashTable
	 */
	public void checkHashTable() {
		for (int tempCounter = 0; tempCounter < this.myHashTable.getSize(); tempCounter++) {
			System.out.println("This is the " + tempCounter
					+ " data  in the HashTable "
					+ this.myHashTable.getData(tempCounter));
		}
	}

	public float getAverageProbeSearch() throws IOException {
		System.out.println("This is times of searching function called "
				+ this.searchInstructionCounter + " .");
		System.out.println("This is the total amount of probes "
				+ this.searchProbeCounter + " .");
		float tempResult = (float) (this.searchProbeCounter)
				/ (float) (this.searchInstructionCounter);
		System.out.println("This is the average of probe of searching "
				+ tempResult + " .");
		this.myWriter.wirteTXT("\n"+"\n"+"This is the average of probe of searching , inserting and deleting not included "+tempResult+"\n");
		System.out.println("This is the total number of looping called  "
				+ this.loopingCounter + " .");
		this.myWriter.closeMyFile();
		return tempResult;
	}
}
